/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package wwcontrolserver;

//note the library location on the SBC has to be annoyingly added to the manifest file for unknown reasons
import com.phidgets.*;
import com.phidgets.event.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.text.SimpleDateFormat;

/**
 *
 * @author Michael Ferry
 */
public class WWControlServer {

    public static final int NumberOfInterfaceKits=4;
    public static final int ifk_pHORP_serial=174418;
    public static final int ifk_HeaterSensor_serial=106721;
    public static final int ifk_HeaterRelay_serial=133211;
    public static final int ifk_MotorRelay_serial=123785;
    public static final int ifk_pHORP_index=0;
    public static final int ifk_HeaterSensor=1;
    public static final int ifk_HeaterRelay=2;
    public static final int ifk_MotorRelay=3;
    public static final double PhidgetsRawSensorDynRange=4096;
    
    public static final int MIN_TO_MILLSEC = 60000;
    public static final int ControlInterval = 1000;
    
    public static final String[] ifks_Name = new String[NumberOfInterfaceKits];   
    private InterfaceKitPhidget[] ifks = new InterfaceKitPhidget[NumberOfInterfaceKits];
    //Determines the default state for the Ratiometric state of each interface kit;
    public static final boolean DefaultRatiometric_pHORP = false;
    public static final boolean DefaultRatiometric_HeaterSensor = true;
    
      
    //DATA COLLECTION VARIABLES
    private Timer DataTimer = null;
    private DataCollectionTaskServer dTask = null;
    private long DataCollectionIntervalMilliSeconds = 60000;
    private String OutputPath = "/home/qbisci";
    private String fSep = System.getProperty("file.separator");
    //DATA COLLECTION VARIABLES
       
    //HEATER CONTROL VARIABLES
    private double[] TempSetPoint = {34.5,34.5,34.5,34.5};
    private double[] TempSetRange = {0.5,0.5,0.5,0.5};
    public static final int[] HeaterSensorMap = {0,1,2,3};
    public static final int[] HeaterSensorToRelayMap = {0,1,2,3};
    private boolean[] HeaterControlState = {false,false,false,false};
    //HEATER CONTROL VARIABLES
    
    //MOTOR CONTROL VARIABLES
    private Timer MotorTimer = null;
    private MotorControlTaskServer mTask = null;
    //Minutes that the motor is running during a cycle
    private long DC1_MotorRunDurationMilli=15*MIN_TO_MILLSEC;
    //Total cycle time in minutes
    private long DC1_MotorPeriodMilli=60*MIN_TO_MILLSEC;
    //private double MotorDutyCycle;
    public static final int DCMotorDO=3;
    //MOTOR CONTROL VARIABLES
    
     
    private ServerSocket ServerSocketToListen;
    private boolean listening = true;
    
    /**
     * @param args the command line arguments
     */
    
    public WWControlServer() {
        ifks_Name[ifk_pHORP_index] = "pHORP";
        ifks_Name[ifk_HeaterSensor] = "HeaterSensor";
        ifks_Name[ifk_HeaterRelay] = "HeaterRelay";
        ifks_Name[ifk_MotorRelay] = "MotorRelay";

        //initComponents();
        SetupInterfaceKits();
        System.out.println(Phidget.getLibraryVersion());


//        
//        //Setup initial Motor control paramters

        //ComputeMotorRunParameters(DC1_MotorRunDuration, DC1_MotorPeriod);
        StartWWControlServer();
        //StartDataCollection(CurrentOutputPath, DataCollectionIntervalMilliSeconds);
        //make sure the motor is turned off when the program begins
        try {
            if (ifks[ifk_MotorRelay].isAttached()) {
                ifks[ifk_MotorRelay].setOutputState(DCMotorDO, false);
            }

        } catch (PhidgetException ex) {
            System.out.println(ex);
        }
    }
    
    private void StartWWControlServer() {
        try {
            ServerSocketToListen = new ServerSocket(4444);
            System.out.println("Server started");
        } catch (IOException e) {
            System.out.println("Could not listen on port: 4444");
            System.exit(-1);
        }
        try {
            while (listening) {
                new WWControlServerMultiThread(this,ServerSocketToListen.accept()).start();
            }
            ServerSocketToListen.close();
        } catch (IOException e) {
            System.out.println(e);
        }
    }

    //private void StartDataCollection(String OutputPath, long DataCollectionIntervalMilliSeconds) {
    public void SetDataCollectionStateServer(boolean state, long IntervalMilliSecondsARG) {
        if (state) {
            if (DataTimer == null) {
                SetDataCollectionInterval(IntervalMilliSecondsARG);
                String[] DataFiles = new String[ifks.length];
                String DatePattern = ("MMddyyyy'_'HHmmss");
                SimpleDateFormat DateFormatter = new SimpleDateFormat(DatePattern);
                Date currTime = new Date();

                for (int i = 0; i < ifks.length; i++) {
                    DataFiles[i] = OutputPath + fSep + DateFormatter.format(currTime) + "_" + ifks_Name[i] + "StateData.txt";
                }
                System.out.println(DataFiles[0]);

                DataTimer = new Timer();
                dTask = new DataCollectionTaskServer(DataFiles, ifks);
                DataTimer.scheduleAtFixedRate(dTask, 0, DataCollectionIntervalMilliSeconds);
                System.out.println("Data Collection task started");

            } else {
                System.out.println("Data Collection already running");
            }
        } else {
            if (DataTimer != null) {
                dTask.cancel();
                DataTimer.cancel();
                dTask = null;
                DataTimer = null;
                System.out.println("Data Collection Ended");
            } else {
                System.out.println("Data Collection not running");
            }
        }
    }
    //Set the data collection interval
    public void SetDataCollectionInterval(long interval){
        DataCollectionIntervalMilliSeconds = interval;
    }
    public void SetComputerMotorControlState(boolean state, long MotorRunDurationMilli, long MotorPeriodMilli) {
        if (state) {
            if (MotorTimer == null) {
                SetMotorRunParameters(MotorRunDurationMilli, MotorPeriodMilli);
                Date StartTime = new Date();
                Date EndTime = null;

                MotorTimer = new Timer();
                mTask = new MotorControlTaskServer(ifks[ifk_MotorRelay], StartTime, EndTime, DC1_MotorRunDurationMilli, DC1_MotorPeriodMilli);
                MotorTimer.scheduleAtFixedRate(mTask, 0, ControlInterval);
                System.out.println("Computer control of DC motor started");
            } else {
                System.out.println("Computer control of DC motor already running");
            }
        } else {
            if (MotorTimer != null) {
                mTask.cancel();
                MotorTimer.cancel();
                mTask = null;
                MotorTimer = null;
                try {
                    if (ifks[ifk_MotorRelay].isAttached()) {
                        ifks[ifk_MotorRelay].setOutputState(DCMotorDO, false);
                    }

                } catch (PhidgetException ex) {
                    System.out.println(ex);
                }

                System.out.println("Computer control of DC motor ended");
            } else {
                //System.out.println("Computer not currently controlling motor");
            }
        }
    }

    public void SetMotorRunParameters(long MotorRunDurationMilli,long MotorPeriodMilli){
        DC1_MotorRunDurationMilli = MotorRunDurationMilli;
        DC1_MotorPeriodMilli = MotorPeriodMilli;
    }

    
    public String GetStatus() {
        String StatusOutput = "";
        try {
            StatusOutput = StatusOutput + "s ifk 0 " + ifks[ifk_pHORP_index].isAttached() + "\n";
            StatusOutput = StatusOutput + "s ifk 1 " + ifks[ifk_HeaterSensor].isAttached() + "\n";
            StatusOutput = StatusOutput + "s ifk 2 " + ifks[ifk_HeaterRelay].isAttached() + "\n";
            StatusOutput = StatusOutput + "s ifk 3 " + ifks[ifk_MotorRelay].isAttached() + "\n";
        } catch (PhidgetException ex) {
            System.out.println(ex);
        }

        if (dTask == null) {
            StatusOutput = StatusOutput + "s data " + "false" + "\n";
        } else {
            StatusOutput = StatusOutput + "s data " + "true " + DataCollectionIntervalMilliSeconds + "\n";
        }
        if (mTask == null) {
            StatusOutput = StatusOutput + "s motor " + "false " + "\n";
        } else {
            StatusOutput = StatusOutput + "s motor " + "true "
                    + DC1_MotorRunDurationMilli + " " + DC1_MotorPeriodMilli + "\n";
        }


        return StatusOutput;
    }
    private void Exit(){
        try {
            //unhook the event listeners
//            ifk.removeSensorChangeListener(sensor_listener);
//            ifk.removeOutputChangeListener(output_listener);
//            ifk.removeInputChangeListener(input_listener);
//            
//            ifk.removeErrorListener(error_listener);
//            ifk.removeDetachListener(detach_listener);
//            ifk.removeAttachListener(attach_listener);

            //close the phidgets and set all digital outputs to zero
            //Shut down all tasks if they are currently running
            if(DataTimer != null) DataTimer.cancel();
            if(dTask != null) dTask.cancel();
//            if(HeaterTimer != null) HeaterTimer.cancel();
//            if(hTask != null) hTask.cancel();
            if(MotorTimer != null) MotorTimer.cancel();
            if(mTask != null) mTask.cancel();
            
            for (int i = 0;i < ifks.length; i++){
                //Shuts off all Digital outputs for safety when the program exits
                if(ifks[i].isAttached()){
                    if(ifks[i].getOutputCount()> 0){
                        for (int j = 0;j < ifks[i].getOutputCount(); j++){
                            //System.out.println("Shutting down output: "+j);
                            ifks[i].setOutputState(j, false);
                        }
                    }
                }
                ifks[i].close();
                ifks[i] = null;
            }
            
            //dispose();
            //System.exit(0);
        } catch (PhidgetException ex) {
            System.out.println(ex);
            //JOptionPane.showMessageDialog(this, ex.getDescription(), "Phidget Error" + ex.getErrorNumber(), JOptionPane.ERROR_MESSAGE);
            //dispose();
            //System.exit(0);
        }
        System.out.print("closing...");
        System.exit(0);
    }
    private void SetupInterfaceKits(){
        try{
        //Setup the pHandORP Phidgets Interface Kit
        ifks[ifk_pHORP_index] = new InterfaceKitPhidget();
        ifks[ifk_pHORP_index].addAttachListener(new AttachListener() {
            
            public void attached(AttachEvent ae) {
                System.out.println("attachment of " + ae);
                //jCheckBox1.setSelected(true);
                try {
                    ifks[ifk_pHORP_index].setRatiometric(DefaultRatiometric_pHORP);
                } catch (PhidgetException e) {
                    System.out.println(e);
                }
                //if(ae.getSource().getSerialNumber(){                   
                //}                   
            }
        });
        ifks[ifk_pHORP_index].addDetachListener(new DetachListener() {

            public void detached(DetachEvent ae) {
                System.out.println("detachment of " + ae);
                //jCheckBox1.setSelected(false);
            }
        });
        ifks[ifk_pHORP_index].addErrorListener(new ErrorListener() {

            public void error(ErrorEvent ee) {
                //System.out.println(ee);
            }
        });
        ifks[ifk_pHORP_index].addInputChangeListener(new InputChangeListener() {

            public void inputChanged(InputChangeEvent oe) {
                //System.out.println(oe);
            }
        });
        ifks[ifk_pHORP_index].addOutputChangeListener(new OutputChangeListener() {

            public void outputChanged(OutputChangeEvent oe) {
                //System.out.println(oe);
            }
        });
        ifks[ifk_pHORP_index].addSensorChangeListener(new SensorChangeListener() {

            public void sensorChanged(SensorChangeEvent se) {
                //System.out.println(se);
            }
        });
        
        //Setup the Heater Sensor Phidgets Interface Kit
        ifks[ifk_HeaterSensor] = new InterfaceKitPhidget();
        ifks[ifk_HeaterSensor].addAttachListener(new AttachListener() {
            
            public void attached(AttachEvent ae) {
                System.out.println("attachment of " + ae);
                //jCheckBox2.setSelected(true);
                try {
                    ifks[ifk_HeaterSensor].setRatiometric(DefaultRatiometric_HeaterSensor);
                } catch (PhidgetException e) {
                    System.out.println(e);
                }
                //if(ae.getSource().getSerialNumber(){                   
                //}                   
            }
        });
        ifks[ifk_HeaterSensor].addDetachListener(new DetachListener() {

            public void detached(DetachEvent ae) {
                System.out.println("detachment of " + ae);
                //jCheckBox2.setSelected(false);
            }
            });
            ifks[ifk_HeaterSensor].addErrorListener(new ErrorListener() {

                public void error(ErrorEvent ee) {
                    //System.out.println(ee);
                }
            });

            ifks[ifk_HeaterSensor].addSensorChangeListener(new SensorChangeListener() {

                public void sensorChanged(SensorChangeEvent se) {
                    int SensorIndex = se.getIndex();
                    for (int i = 0; i < HeaterSensorMap.length; i++) {
                        if (SensorIndex == HeaterSensorMap[i]) {
                            if (HeaterControlState[i]) {
                                ControlFunctionsServer.HeaterControl(SensorIndex, ifks[ifk_HeaterSensor],
                                        HeaterSensorToRelayMap[i], ifks[ifk_HeaterRelay], TempSetPoint[i], TempSetRange[i]);
                            }
                        }

                    }
                    //System.out.println(se);
                }
            });
        
        //Setup the Motor Relay Interface Kit
        ifks[ifk_HeaterRelay] = new InterfaceKitPhidget();
        ifks[ifk_HeaterRelay].addAttachListener(new AttachListener() {
            
            public void attached(AttachEvent ae) {
                System.out.println("attachment of " + ae);
                //jCheckBox3.setSelected(true);
                //if(ae.getSource().getSerialNumber(){                   
                //}                   
            }
        });
        ifks[ifk_HeaterRelay].addDetachListener(new DetachListener() {

            public void detached(DetachEvent ae) {
                System.out.println("detachment of " + ae);
                //jCheckBox3.setSelected(false);
            }
        });
        ifks[ifk_HeaterRelay].addErrorListener(new ErrorListener() {

            public void error(ErrorEvent ee) {
                //System.out.println(ee);
            }
        });
        
        ifks[ifk_HeaterRelay].addOutputChangeListener(new OutputChangeListener() {

            public void outputChanged(OutputChangeEvent oe) {
             
                //System.out.println(oe);
            }
        });
        
        //Setup the Heater Relay Interface Kit
        ifks[ifk_MotorRelay] = new InterfaceKitPhidget();
        ifks[ifk_MotorRelay].addAttachListener(new AttachListener() {
            
            public void attached(AttachEvent ae) {
                System.out.println("attachment of " + ae);
                //jCheckBox4.setSelected(true);
                //if(ae.getSource().getSerialNumber(){                   
                //}                   
            }
        });
        ifks[ifk_MotorRelay].addDetachListener(new DetachListener() {

            public void detached(DetachEvent ae) {
                System.out.println("detachment of " + ae);
                //jCheckBox4.setSelected(false);
            }
        });
        ifks[ifk_MotorRelay].addErrorListener(new ErrorListener() {

            public void error(ErrorEvent ee) {
                //System.out.println(ee);
            }
        });
        
        ifks[ifk_MotorRelay].addOutputChangeListener(new OutputChangeListener() {

            public void outputChanged(OutputChangeEvent oe) {
                //System.out.println(oe);
                try{
                    if(ifks[ifk_MotorRelay].isAttached()){
                        //Check to see if the Motor is currently enabled
                        if(ifks[ifk_MotorRelay].getOutputState(DCMotorDO)){
                            //jButton4.setEnabled(false);
                            //jButton5.setEnabled(true); 
                            //jLabel8.setText("Motor is currently: ON");
                        }else{
                            //jButton4.setEnabled(true);
                            //jButton5.setEnabled(false);
                            //jLabel8.setText("Motor is currently: OFF");
                        }                       
                    }
                }catch(PhidgetException ex){
                    System.out.println(ex);
                }
            }
        });
        
        
        ifks[ifk_pHORP_index].open(ifk_pHORP_serial);
        ifks[ifk_HeaterSensor].open(ifk_HeaterSensor_serial);
        ifks[ifk_HeaterRelay].open(ifk_HeaterRelay_serial);
        ifks[ifk_MotorRelay].open(ifk_MotorRelay_serial);
        
        
        
        }catch(PhidgetException ex){
            System.out.println(ex.getDescription()+ "Phidget Error" + ex.getErrorNumber());
            //JOptionPane.showMessageDialog(this, ex.getDescription(), "Phidget Error" + ex.getErrorNumber(), JOptionPane.ERROR_MESSAGE);
            //dispose();
            //System.exit(0);
        };
    }
    /**
     * @param args the command line arguments
     */
   
    
    public static void main(String[] args) {
        // TODO code application logic here
        //System.out.println("Hello World!");
        WWControlServer s1 = new WWControlServer();
        while(true);
        
    }
}
